#include <buola/scene/geodes/csphere.h>
#include <buola/scene/cmesh.h>
#include <buola/scene/cvertexdata.h>
#include <buola/scene/cindexdata.h>
#include <buola/scene/cmeshbuilder.h>
#include <BulletCollision/CollisionShapes/btSphereShape.h>

namespace buola { namespace scene {

static PMesh sphere_mesh(int pRings,int pSegments)
{
    PMesh lMesh=new CMesh;
    
    CVertexData &lVertexData=lMesh->VertexData();
    
    lVertexData.AddField<float>(FIELD_POSITION,3);
    lVertexData.AddField<float>(FIELD_NORMAL,3);
    lVertexData.AddField<float>(FIELD_TEXCOORD,2);

    lVertexData.Resize((pRings+1)*(pSegments+1));

    struct ATTRIBUTE_PACKED LVertex
    {
        float x,y,z;
        float nx,ny,nz;
        float u,v;
    };
    
    LVertex *lVertices=lVertexData.Map<LVertex>();

    CIndexData &lIndexData=lMesh->IndexData();
    
    lIndexData.Resize(6*pRings*(pSegments+1));
    
    uint32_t *lIndices=lIndexData.Map();
    
    float lDeltaRingAngle=M_PI/pRings;
    float lDeltaSegAngle=2*M_PI/pSegments;
    
    int lVertexIndex=0;
    
    for(int lRing=0;lRing<=pRings;lRing++)
    {
        float lR0=sin(lRing*lDeltaRingAngle);
        float lY0=cos(lRing*lDeltaRingAngle);
        
        for(int lSeg=0;lSeg<=pSegments;lSeg++)
        {
            float lX0=lR0*sin(lSeg*lDeltaSegAngle);
            float lZ0=lR0*cos(lSeg*lDeltaSegAngle);
            
            lVertices->x=lX0;
            lVertices->y=lY0;
            lVertices->z=lZ0;
            
            mat::CVec3f lNormal=normalize(mat::CVec3f(lX0,lY0,lZ0));
            
            lVertices->nx=lNormal.x();
            lVertices->ny=lNormal.y();
            lVertices->nz=lNormal.z();
            
            if(lRing!=pRings)
            {
                *lIndices++=lVertexIndex+pSegments+1;
                *lIndices++=lVertexIndex;
                *lIndices++=lVertexIndex+pSegments;
                *lIndices++=lVertexIndex+pSegments+1;
                *lIndices++=lVertexIndex+1;
                *lIndices++=lVertexIndex;
            }
            lVertices++;
            lVertexIndex++;
        }
    }
    
    lVertexData.Unmap();
    lIndexData.Unmap();
    
    lMesh->AddSubMesh("sphere",EPrimitive::TRIANGLES,0,6*pRings*(pSegments+1));

    return lMesh;
}
  
CSphere::CSphere(int pRings,int pSegments)
    :   CGeode(sphere_mesh(pRings,pSegments))
{
}

CSphere::~CSphere()
{
}

PBulletCollisionShape CSphere::GetCollisionShape()
{
    return PBulletCollisionShape(new btSphereShape(1.0));
}

/*namespace gl*/ } /*namespace buola*/ }
